/* __auth__ : KunLin */
package com.cskaoyan.service;


import com.cskaoyan.bean.*;
import com.cskaoyan.bean.bo.goods.*;
import com.cskaoyan.bean.category.Category;
import com.cskaoyan.bean.category.CategoryExample;
import com.cskaoyan.bean.user.CollectExample;
import com.cskaoyan.bean.vo.goods.*;
import com.cskaoyan.mapper.*;
import com.cskaoyan.utils.Constant;
import com.cskaoyan.utils.CopyModuleClassUtils;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.Fuzziness;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.SuggestBuilders;
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder;
import org.elasticsearch.search.suggest.term.TermSuggestion;
import org.elasticsearch.search.suggest.term.TermSuggestionBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

import static com.cskaoyan.utils.CommonUtil.objectIsEmpty;


@Service
public class GoodsServiceImpl implements GoodsService {
    @Autowired
    GoodsMapper goodsMapper;

    @Autowired
    CategoryMapper categoryMapper;

    @Autowired
    BrandMapper brandMapper;

    @Autowired
    GoodsAttributeMapper goodsAttributeMapper;

    @Autowired
    GoodsSpecificationMapper goodsSpecificationMapper;

    @Autowired
    GoodsProductMapper goodsProductMapper;

    @Autowired
    IssueMapper issueMapper;

    @Autowired
    CollectMapper collectMapper;

    @Autowired
    CommentMapper commentMapper;

    @Autowired
    GoodsElasticsearchMapper goodsElasticsearchMapper;

    @Autowired
    RestHighLevelClient restHighLevelClient;

    @Autowired
    UserMapper userMapper;

    @Override
    public GoodsListVO queryAllGoods(GoodsListBO goodsListBO) {
        GoodsListVO goodsListVO = new GoodsListVO();
        goodsListVO.setData(new GoodsListVO.GoodsListData());
        goodsListVO.getData().setList(new LinkedList<>());

        // 情况①接口只会返回一个商品详情
        String goodsSn = goodsListBO.getGoodsSn();
        Integer goodsId = goodsListBO.getGoodsId();
        String name = goodsListBO.getName();
        Goods goods;
        if (!objectIsEmpty(goodsSn) && !objectIsEmpty(goodsId) && !objectIsEmpty(name)) {
            goods = goodsElasticsearchMapper.findByGoodsSnAndIdAndNameLike(goodsSn, goodsId, name);
            return hitsOne(goodsListVO, goods);
        }
        if (!objectIsEmpty(goodsSn) && !objectIsEmpty(goodsId)) {
            goods = goodsElasticsearchMapper.findByGoodsSnAndId(goodsSn, goodsId);
            return hitsOne(goodsListVO, goods);
        }
        if (!objectIsEmpty(goodsSn) && !objectIsEmpty(name)) {
            goods = goodsElasticsearchMapper.findByGoodsSnAndNameLike(goodsSn, name);
            return hitsOne(goodsListVO, goods);
        }
        if (!objectIsEmpty(goodsId) && !objectIsEmpty(name)) {
            goods = goodsElasticsearchMapper.findByIdAndNameLike(goodsId, name);
            return hitsOne(goodsListVO, goods);
        }
        if (!objectIsEmpty(goodsId)) {
            goods = goodsElasticsearchMapper.findById(goodsId);
            return hitsOne(goodsListVO, goods);
        }
        if (!objectIsEmpty(goodsSn)) {
            goods = goodsElasticsearchMapper.findByGoodsSn(goodsSn);
            return hitsOne(goodsListVO, goods);
        }

        // 情况②接口返回多条商品无需排序
        if (!objectIsEmpty(goodsListBO.getLimit()) && goodsListBO.getLimit() == 0) {
            Iterable<Goods> goodsIterable = goodsElasticsearchMapper.findAll();
            return hitsMany(goodsListVO, goodsIterable);
        }

        // 设置排序方式和按照什么方式进行排序
        // 返回多条商品且需要排序
        Sort sort = Sort.by(Sort.Direction.fromString(goodsListBO.getOrder()), goodsListBO.getSort());
        // 得到起始页
        int offset = (goodsListBO.getPage() - 1) * goodsListBO.getLimit();
        PageRequest request = PageRequest.of(offset, goodsListBO.getLimit(), sort);
        Page<Goods> goodsPage;
        if (!objectIsEmpty(name)) {
            goodsPage = goodsElasticsearchMapper.findByName(name, request);
        } else {
            // 分页查询信息
            goodsPage = goodsElasticsearchMapper.findAll(request);
        }
        for (Goods g : goodsPage.getContent()) {
            goodsListVO.getData().getList().add(g);

        }
        goodsListVO.getData().setPages(goodsPage.getTotalPages());
        goodsListVO.getData().setLimit(goodsListBO.getLimit());
        goodsListVO.getData().setPage(goodsListBO.getPage());
        goodsListVO.getData().setTotal((int) goodsPage.getTotalElements());

        return goodsListVO.success();
    }

    private GoodsListVO hitsMany(GoodsListVO goodsListVO, Iterable<Goods> goodsIterable) {

        goodsListVO.getData().setLimit(0);
        goodsListVO.getData().setPage(0);
        goodsListVO.getData().setPages(0);
        goodsIterable.forEach((goods) -> {
            goodsListVO.getData().getList().add(goods);
        });
        goodsListVO.getData().setTotal(goodsListVO.getData().getList().size());
        return goodsListVO.success();
    }

    private GoodsListVO hitsOne(GoodsListVO goodsListVO, Goods goods) {
        goodsListVO.getData().setPages(0);
        goodsListVO.getData().setLimit(0);
        goodsListVO.getData().setPage(0);
        goodsListVO.getData().setTotal(0);
        if (goods != null) {
            goodsListVO.getData().getList().add(goods);
            goodsListVO.getData().setPages(1);
            goodsListVO.getData().setLimit(20);
            goodsListVO.getData().setPage(1);
            goodsListVO.getData().setTotal(1);
        }
        return goodsListVO.success();
    }


    @Override
    public GoodsCatAndBrandVO queryCategoryAndBrand() {
        GoodsCatAndBrandVO goodsCatAndBrandVO = new GoodsCatAndBrandVO();

        GoodsCatAndBrandVO.DataDTO data = new GoodsCatAndBrandVO.DataDTO();
        data.setCategoryList(new LinkedList<>());
        goodsCatAndBrandVO.setData(data);

        // 查询所有的父级数据
        List<GoodsMapArgs> goodsMapArgsList = categoryMapper.queryAllPidAndLabel();
        for (GoodsMapArgs goodsMapArgs : goodsMapArgsList) {
            GoodsCatAndBrandVO.CategoryListDTO categoryListDTO = CopyModuleClassUtils.bean2vo(goodsMapArgs, GoodsCatAndBrandVO.CategoryListDTO.class);
            categoryListDTO.setChildren(new LinkedList<>());

            // 通过pid去查询Children数据
            List<GoodsMapArgs> childrenGoodsMapArgsList = categoryMapper.queryIdAndNameByPid(goodsMapArgs.getValue());
            for (GoodsMapArgs mapArgs : childrenGoodsMapArgsList) {
                GoodsCatAndBrandVO.ChildrenDTO childrenDTO = CopyModuleClassUtils.bean2vo(mapArgs, GoodsCatAndBrandVO.ChildrenDTO.class);
                categoryListDTO.getChildren().add(childrenDTO);
            }
            data.getCategoryList().add(categoryListDTO);
        }

        data.setBrandList(new LinkedList<>());
        // 查询索引制造商
        List<GoodsMapArgs> goodsMapArgs = brandMapper.queryAllIdAndName();
        for (GoodsMapArgs goodsMapArg : goodsMapArgs) {
            GoodsCatAndBrandVO.BrandListDTO brandListDTO = CopyModuleClassUtils.bean2vo(goodsMapArg, GoodsCatAndBrandVO.BrandListDTO.class);
            data.getBrandList().add(brandListDTO);
        }
        return goodsCatAndBrandVO.success();
    }


    @Override
    public GoodsDetailVO queryGoodsDetail(Integer id) {
        GoodsDetailVO goodsDetailVO = new GoodsDetailVO();
        GoodsDetailVO.DataDTO dataDTO = new GoodsDetailVO.DataDTO();
        goodsDetailVO.setData(dataDTO);

        Goods goods = goodsMapper.selectByPrimaryKey(id);

        goodsDetailVO.getData().setCategoryIds(goods.getCategoryId());
        dataDTO.setGoods(CopyModuleClassUtils.bean2vo(goods, GoodsDetailVO.GoodsDTO.class));

        goodsDetailVO.getData().setAttributes(new LinkedList<>());

        GoodsAttributeExample goodsAttributeExample = new GoodsAttributeExample();
        goodsAttributeExample.createCriteria().andGoodsIdEqualTo(goods.getId());
        List<GoodsAttribute> goodsAttributes = goodsAttributeMapper.selectByExample(goodsAttributeExample);
        for (GoodsAttribute goodsAttribute : goodsAttributes) {
            GoodsDetailVO.AttributesDTO attributesDTO = CopyModuleClassUtils.bean2vo(goodsAttribute, GoodsDetailVO.AttributesDTO.class);
            goodsDetailVO.getData().getAttributes().add(attributesDTO);
        }

        goodsDetailVO.getData().setSpecifications(new LinkedList<>());

        GoodsSpecificationExample goodsSpecificationExample = new GoodsSpecificationExample();
        goodsSpecificationExample.createCriteria().andGoodsIdEqualTo(goods.getId());
        List<GoodsSpecification> goodsSpecifications = goodsSpecificationMapper.selectByExample(goodsSpecificationExample);

        for (GoodsSpecification goodsSpecification : goodsSpecifications) {
            GoodsDetailVO.SpecificationsDTO specificationsDTO = CopyModuleClassUtils.bean2vo(goodsSpecification, GoodsDetailVO.SpecificationsDTO.class);
            goodsDetailVO.getData().getSpecifications().add(specificationsDTO);
        }

        goodsDetailVO.getData().setProducts(new LinkedList<>());
        GoodsProductExample goodsProductExample = new GoodsProductExample();
        goodsProductExample.createCriteria().andGoodsIdEqualTo(goods.getId());
        List<GoodsProduct> goodsProducts = goodsProductMapper.selectByExample(goodsProductExample);
        for (GoodsProduct goodsProduct : goodsProducts) {
            GoodsDetailVO.ProductsDTO productsDTO = CopyModuleClassUtils.bean2vo(goodsProduct, GoodsDetailVO.ProductsDTO.class);
            goodsDetailVO.getData().getProducts().add(productsDTO);
        }
        return goodsDetailVO.success();
    }

    @Override
    public GoodsCreateVO create(GoodsCreateBO goodsCreateBO) {
        Integer result = createGoods(goodsCreateBO);
        return new GoodsCreateVO().success();
    }

    @Transactional(rollbackFor = Exception.class)
    public Integer createGoods(GoodsCreateBO goodsCreateBO) {
        // 添加商品
        Goods goods = CopyModuleClassUtils.bo2bean(goodsCreateBO.getGoods(), Goods.class);

        // 对galleryUrl进行域与资源分离
//        String[] gallery = goods.getGallery();
//        String[] newGallery = new String[gallery.length];
//        for (int i = 0; i < gallery.length; i++) {
//            newGallery[i] =  splitUrlResource(gallery[i]);
//        }
//        goods.setGallery(newGallery);
//
//        // 对picUrl进行域与资源分离
//        goods.setPicUrl(splitUrlResource(goods.getPicUrl()));

        goods.setAddTime(new Date());
        goods.setUpdateTime(new Date());

        // 保存到MySQL
        goodsMapper.insertGoods(goods);

        // 保存到 Elasticsearch
        goodsElasticsearchMapper.save(goods);

        for (GoodsCreateBO.SpecificationsDTO specification : goodsCreateBO.getSpecifications()) {
            // 添加商品规格
            GoodsSpecification goodsSpecification = CopyModuleClassUtils.bo2bean(specification, GoodsSpecification.class);
            goodsSpecification.setGoodsId(goods.getId());
            goodsSpecification.setAddTime(goods.getAddTime());
            goodsSpecification.setUpdateTime(goods.getUpdateTime());
            // 对picUrl进行域与资源分离
//            specification.setPicUrl(splitUrlResource(specification.getPicUrl()));
            goodsSpecificationMapper.insertSpecification(goodsSpecification);
        }

        for (GoodsCreateBO.AttributesDTO attribute : goodsCreateBO.getAttributes()) {
            // 添加商品属性
            GoodsAttribute goodsAttribute = CopyModuleClassUtils.bo2bean(attribute, GoodsAttribute.class);
            goodsAttribute.setGoodsId(goods.getId());
            goodsAttribute.setAddTime(goods.getAddTime());
            goodsAttribute.setAddTime(goods.getUpdateTime());
            goodsAttributeMapper.insertAttribute(goodsAttribute);
        }

        for (GoodsCreateBO.ProductsDTO product : goodsCreateBO.getProducts()) {
            // 制造商
            GoodsProduct goodsProduct = CopyModuleClassUtils.bo2bean(product, GoodsProduct.class);
            goodsProduct.setGoodsId(goods.getId());
            goodsProduct.setAddTime(goods.getAddTime());
            goodsProduct.setUpdateTime(goods.getUpdateTime());
            // 对url进行域与资源分离
//            goodsProduct.setUrl(splitUrlResource(goodsProduct.getUrl()));
            goodsProductMapper.insertProduct(goodsProduct);
        }
        return 1;

    }

    @Override
    public GoodsUpdateVO update(GoodsUpdateBO goodsUpdateBO) {
        Integer result = updateGoods(goodsUpdateBO);
        return new GoodsUpdateVO().success();
    }

    private Integer updateGoods(GoodsUpdateBO goodsUpdateBO) {
        Goods goods = CopyModuleClassUtils.bo2bean(goodsUpdateBO.getGoods(), Goods.class);
        // 对galleryUrl进行域与资源分离
//        String[] gallery = goods.getGallery();
//        String[] newGallery = new String[gallery.length];
//        for (int i = 0; i < gallery.length; i++) {
//            newGallery[i] =  splitUrlResource(gallery[i]);
//        }
//        goods.setGallery(newGallery);
//        // 对picUrl进行域与资源分离
//        goods.setPicUrl(splitUrlResource(goods.getPicUrl()));

        goodsMapper.updateByPrimaryKeySelective(goods);

        goodsElasticsearchMapper.save(goods);

        for (GoodsUpdateBO.AttributesDTO attribute : goodsUpdateBO.getAttributes()) {
            GoodsAttribute goodsAttribute = CopyModuleClassUtils.bo2bean(attribute, GoodsAttribute.class);
            goodsAttributeMapper.updateByPrimaryKeySelective(goodsAttribute);
        }

        for (GoodsUpdateBO.SpecificationsDTO specification : goodsUpdateBO.getSpecifications()) {
            GoodsSpecification goodsSpecification = CopyModuleClassUtils.bo2bean(specification, GoodsSpecification.class);
            // 对picUrl进行域与资源分离
//            specification.setPicUrl(splitUrlResource(specification.getPicUrl()));
            goodsSpecificationMapper.updateByPrimaryKeySelective(goodsSpecification);
        }

        for (GoodsUpdateBO.ProductsDTO product : goodsUpdateBO.getProducts()) {
            GoodsProduct goodsProduct = CopyModuleClassUtils.bo2bean(product, GoodsProduct.class);
            // 对url进行域与资源分离
//            goodsProduct.setUrl(splitUrlResource(goodsProduct.getUrl()));
            goodsProductMapper.updateByPrimaryKeySelective(goodsProduct);
        }
        return 1;
    }

    @Override
    public GoodsDeleteVo delete(GoodsDeleteBo goodsDeleteBo) {
        Integer result = deleteGoods(goodsDeleteBo);
        return new GoodsDeleteVo().success();
    }

    @Override
    public WXGoodsCountVO queryGoodsCount() {
        Long result = goodsMapper.countByExample(new GoodsExample());
        return new WXGoodsCountVO().success(result);
    }

    @Override
    public WXGoodsCategoryVO queryCategoryStuff(Integer id) {
        WXGoodsCategoryVO goodsCategoryVO = new WXGoodsCategoryVO();
        goodsCategoryVO.setData(new WXGoodsCategoryVO.DataDTO());

        //一节标题{}
        Category category1 = categoryMapper.selectByPrimaryKey(id);
        if ("L2".equals(category1.getLevel())){
            // 当前
            WXGoodsCategoryVO.DataDTO.CurrentCategoryDTO currentCategoryDTO = CopyModuleClassUtils.bean2vo(category1, WXGoodsCategoryVO.DataDTO.CurrentCategoryDTO.class);
            goodsCategoryVO.getData().setCurrentCategory(currentCategoryDTO);

            // 父
            Category category = categoryMapper.selectByPrimaryKey(category1.getPid());
            WXGoodsCategoryVO.DataDTO.ParentCategoryDTO parentCategoryDTO = CopyModuleClassUtils.bean2vo(category, WXGoodsCategoryVO.DataDTO.ParentCategoryDTO.class);
            goodsCategoryVO.getData().setParentCategory(parentCategoryDTO);

            // 兄弟
            CategoryExample categoryExample = new CategoryExample();
            categoryExample.createCriteria().andPidEqualTo(category.getId()).andDeletedEqualTo(false);
            List<Category> brotherCategories = categoryMapper.selectByExample(categoryExample);
            goodsCategoryVO.getData().setBrotherCategory(new LinkedList<>());
            for (Category  category2: brotherCategories) {
                WXGoodsCategoryVO.DataDTO.BrotherCategoryDTO brotherCategoryDTO = CopyModuleClassUtils.bean2vo(category2, WXGoodsCategoryVO.DataDTO.BrotherCategoryDTO.class);
                goodsCategoryVO.getData().getBrotherCategory().add(brotherCategoryDTO);
            }
            return goodsCategoryVO.success();
        }



        // 父级数据
        Category parentCategory = categoryMapper.selectByPrimaryKey(id);
        WXGoodsCategoryVO.DataDTO.ParentCategoryDTO parentCategoryDTO = CopyModuleClassUtils.bean2vo(parentCategory, WXGoodsCategoryVO.DataDTO.ParentCategoryDTO.class);
        goodsCategoryVO.getData().setParentCategory(parentCategoryDTO);

        // 二级标题
        // 兄弟
        CategoryExample categoryExample = new CategoryExample();
        categoryExample.createCriteria().andPidEqualTo(parentCategory.getId()).andDeletedEqualTo(false);
        List<Category> brotherCategories = categoryMapper.selectByExample(categoryExample);
        int i = 0;
        goodsCategoryVO.getData().setBrotherCategory(new LinkedList<>());
        for (Category category : brotherCategories) {
            if (i == 0){
                WXGoodsCategoryVO.DataDTO.CurrentCategoryDTO currentCategoryDTO = CopyModuleClassUtils.bean2vo(category, WXGoodsCategoryVO.DataDTO.CurrentCategoryDTO.class);
                goodsCategoryVO.getData().setCurrentCategory(currentCategoryDTO);
                i++;
            }
            WXGoodsCategoryVO.DataDTO.BrotherCategoryDTO brotherCategoryDTO = CopyModuleClassUtils.bean2vo(category, WXGoodsCategoryVO.DataDTO.BrotherCategoryDTO.class);
            goodsCategoryVO.getData().getBrotherCategory().add(brotherCategoryDTO);
        }
        return goodsCategoryVO.success();

    }

    @Override
    public WXGoodsListVO queryListStuff(WXGoodsListBO wxGoodsListBO) {
        List<Goods> goodsList = null;
        if (!objectIsEmpty(wxGoodsListBO.getKeyword())) {
            // 关键字搜索
            goodsList = queryListStuffByKeyword(wxGoodsListBO);
        }

        if (!objectIsEmpty(wxGoodsListBO.getBrandId())) {
            // 相关品牌下的商品
            GoodsExample goodsExample = new GoodsExample();
            goodsExample.createCriteria().andBrandIdEqualTo(wxGoodsListBO.getBrandId());
            goodsList = goodsMapper.selectByExample(goodsExample);
            if (goodsList != null && !goodsList.isEmpty()) {
                Integer categoryId = goodsList.get(0).getCategoryId();
                wxGoodsListBO.setCategoryId(categoryId);
            }
        }


        PageHelper.startPage(wxGoodsListBO.getPage(), wxGoodsListBO.getLimit());

        WXGoodsListVO wxGoodsListVO = new WXGoodsListVO();
        WXGoodsListVO.DataDTO data = new WXGoodsListVO.DataDTO();

        // 相关品类下的商品
        if (goodsList == null || goodsList.isEmpty()) {
            GoodsExample goodsExample = new GoodsExample();

            GoodsExample.Criteria criteria = goodsExample.createCriteria().andDeletedEqualTo(false);
            if (!objectIsEmpty(wxGoodsListBO.getCategoryId()) && !(wxGoodsListBO.getCategoryId().equals(0))) {
                criteria.andCategoryIdEqualTo(wxGoodsListBO.getCategoryId());
            }

            if (!objectIsEmpty(wxGoodsListBO.getIsHot())) {
                criteria.andIsHotEqualTo(wxGoodsListBO.getIsHot());
            }

            if (!objectIsEmpty(wxGoodsListBO.getIsNew())) {
                criteria.andIsNewEqualTo(wxGoodsListBO.getIsNew());
            }

            if (!objectIsEmpty(wxGoodsListBO.getSort()) &&
                    !objectIsEmpty(wxGoodsListBO.getOrder())) {
                goodsExample.setOrderByClause(wxGoodsListBO.getSort() + " " + wxGoodsListBO.getOrder());
            }
            goodsList = goodsMapper.selectByExample(goodsExample);
        }
        PageInfo<Goods> goodsPageInfo = new PageInfo<>(goodsList);
        data.setPages(goodsPageInfo.getPages());
        data.setLimit(goodsPageInfo.getPageSize());
        data.setPage(goodsPageInfo.getPageNum());
        data.setTotal(goodsPageInfo.getTotal());
        wxGoodsListVO.setData(data);
        wxGoodsListVO.getData().setList(new LinkedList<>());
        for (Goods goods : goodsList) {
            WXGoodsListVO.DataDTO.ListDTO listDTO = CopyModuleClassUtils.bean2vo(goods, WXGoodsListVO.DataDTO.ListDTO.class);
            wxGoodsListVO.getData().getList().add(listDTO);
        }


        wxGoodsListVO.getData().setFilterCategoryList(new LinkedList<>());
        // 兄弟类别
        if (wxGoodsListBO.getCategoryId() != null && !wxGoodsListBO.getCategoryId().equals(0)) {
            Category category = categoryMapper.selectByPrimaryKey(wxGoodsListBO.getCategoryId());
            CategoryExample categoryExample = new CategoryExample();
            categoryExample.createCriteria().andPidEqualTo(category.getPid());
            List<Category> categories = categoryMapper.selectByExample(categoryExample);

            for (Category category1 : categories) {
                WXGoodsListVO.DataDTO.FilterCategoryListDTO filterCategoryListDTO = CopyModuleClassUtils.bean2vo(category1, WXGoodsListVO.DataDTO.FilterCategoryListDTO.class);
                wxGoodsListVO.getData().getFilterCategoryList().add(filterCategoryListDTO);
            }
        }else {
            // 获取前10个商品的子类并返回
            Set<Integer> goodsListCategory = new HashSet<>();
            for (Goods goods : goodsList) {
                goodsListCategory.add(goods.getCategoryId());
            }
            for (Integer integer : goodsListCategory) {
                Category category = categoryMapper.selectByPrimaryKey(integer);
                if (category != null){
                    WXGoodsListVO.DataDTO.FilterCategoryListDTO filterCategoryListDTO = CopyModuleClassUtils.bean2vo(category, WXGoodsListVO.DataDTO.FilterCategoryListDTO.class);
                    wxGoodsListVO.getData().getFilterCategoryList().add(filterCategoryListDTO);
                }
            }
        }
        return wxGoodsListVO.success();
    }

    private List<Goods> queryListStuffByKeyword(WXGoodsListBO wxGoodsListBO) {
        String keyword = wxGoodsListBO.getKeyword();

        List<Goods> goodsElasticsearchMapperByName = goodsElasticsearchMapper.findByName(keyword);
        LinkedList<Goods> goods = new LinkedList<>(goodsElasticsearchMapperByName);

        List<Goods> byKeywords = goodsElasticsearchMapper.findByKeywords(keyword);
        goods.addAll(byKeywords);

        List<Goods> byBrief = goodsElasticsearchMapper.findByBrief(keyword);
        goods.addAll(byBrief);
        return goods;
    }


    @Override
    public WXGoodsDetailVO queryDetailStuff(Integer id) {
        WXGoodsDetailVO wxGoodsDetailVO = new WXGoodsDetailVO();
        WXGoodsDetailVO.DataDTO data = new WXGoodsDetailVO.DataDTO();
        wxGoodsDetailVO.setData(data);

        // 商品信息
        Goods goodsInfo = goodsMapper.selectByPrimaryKey(id);
        WXGoodsDetailVO.DataDTO.InfoDTO infoDTO = CopyModuleClassUtils.bean2vo(goodsInfo, WXGoodsDetailVO.DataDTO.InfoDTO.class);
        data.setInfo(infoDTO);


        data.setSpecificationList(new LinkedList<>());
        // 商品规格
        GoodsSpecificationExample goodsSpecificationExample = new GoodsSpecificationExample();
        goodsSpecificationExample.createCriteria().andGoodsIdEqualTo(goodsInfo.getId()).andDeletedEqualTo(false);
        List<GoodsSpecification> goodsSpecifications = goodsSpecificationMapper.selectByExample(goodsSpecificationExample);
        for (GoodsSpecification goodsSpecification : goodsSpecifications) {
            WXGoodsDetailVO.DataDTO.SpecificationListDTO specificationListDTO = new WXGoodsDetailVO.DataDTO.SpecificationListDTO();
            specificationListDTO.setValueList(new LinkedList<>());
            specificationListDTO.setName(goodsSpecification.getSpecification());
            WXGoodsDetailVO.DataDTO.SpecificationListDTO.ValueListDTO valueListDTO = CopyModuleClassUtils.bean2vo(goodsSpecification, WXGoodsDetailVO.DataDTO.SpecificationListDTO.ValueListDTO.class);
            specificationListDTO.getValueList().add(valueListDTO);
            data.getSpecificationList().add(specificationListDTO);
        }

        // 商品团购直接置空List
        data.setGroupon(new LinkedList<>());


        data.setIssue(new LinkedList<>());
        // 商品问题List
        IssueExample issueExample = new IssueExample();
        issueExample.createCriteria().andDeletedEqualTo(false);
        List<Issue> issues = issueMapper.selectByExample(issueExample);
        for (Issue issue : issues) {
            WXGoodsDetailVO.DataDTO.IssueDTO issueDTO = CopyModuleClassUtils.bean2vo(issue, WXGoodsDetailVO.DataDTO.IssueDTO.class);
            data.getIssue().add(issueDTO);
        }


        // 用户是否收藏
        if (objectIsEmpty(getUserId())) {
            data.setUserHasCollect(0);
        } else {
            CollectExample collectExample = new CollectExample();
            collectExample.createCriteria()
                    .andTypeEqualTo((byte) 0)
                    .andValueIdEqualTo(goodsInfo.getId())
                    .andDeletedEqualTo(false)
                    .andUserIdEqualTo(getUserId());
            long l = collectMapper.countByExample(collectExample);
            if (0 != l) {
                data.setUserHasCollect(1);
            }
        }

        // 分享图片
        String shareUrl = goodsInfo.getShareUrl();
        data.setShareImage(shareUrl);


        data.setComment(new WXGoodsDetailVO.DataDTO.CommentDTO());
        data.getComment().setData(new LinkedList<>());
        // 商品评论

        CommentExample commentExample = new CommentExample();
        commentExample.createCriteria().andTypeEqualTo((byte) 0).andValueIdEqualTo(goodsInfo.getId()).andDeletedEqualTo(false);
        List<Comment> comments = commentMapper.selectByExample(commentExample);

        ConcurrentHashMap<String, String> concurrentHashMap = new ConcurrentHashMap<>();
        concurrentHashMap.put("picUrls", "picList");
        for (Comment comment : comments) {
            WXGoodsDetailVO.CommentDataDTO commentDataDTO = CopyModuleClassUtils.bean2vo(comment, WXGoodsDetailVO.CommentDataDTO.class, concurrentHashMap);
            User user = userMapper.selectByPrimaryKey(comment.getUserId());
            commentDataDTO.setAvatar(user.getAvatar());
            commentDataDTO.setNickname(user.getNickname());
            data.getComment().getData().add(commentDataDTO);
        }
        data.getComment().setCount(comments.size());

        // 是否能分享,看不懂。直接 true
        data.setShare(true);


        data.setAttribute(new LinkedList<>());
        // 商品属性
        GoodsAttributeExample goodsAttributeExample = new GoodsAttributeExample();
        goodsAttributeExample.createCriteria().andGoodsIdEqualTo(goodsInfo.getId()).andDeletedEqualTo(false);
        List<GoodsAttribute> goodsAttributes = goodsAttributeMapper.selectByExample(goodsAttributeExample);
        for (GoodsAttribute goodsAttribute : goodsAttributes) {
            WXGoodsDetailVO.DataDTO.AttributeDTO attributeDTO = CopyModuleClassUtils.bean2vo(goodsAttribute, WXGoodsDetailVO.DataDTO.AttributeDTO.class);
            data.getAttribute().add(attributeDTO);
        }


        // 商品品牌
        Integer brandId = goodsInfo.getBrandId();
        if (brandId != 0) {
            Brand brand = brandMapper.selectByPrimaryKey(brandId);
            WXGoodsDetailVO.DataDTO.BrandDTO brandDTO = CopyModuleClassUtils.bean2vo(brand, WXGoodsDetailVO.DataDTO.BrandDTO.class);
            data.setBrand(brandDTO);
        }

        data.setProductList(new LinkedList<>());
        // 商品生产List
        GoodsProductExample goodsProductExample = new GoodsProductExample();
        goodsProductExample.createCriteria().andGoodsIdEqualTo(goodsInfo.getId()).andDeletedEqualTo(false);
        List<GoodsProduct> goodsProducts = goodsProductMapper.selectByExample(goodsProductExample);
        for (GoodsProduct goodsProduct : goodsProducts) {
            WXGoodsDetailVO.DataDTO.ProductListDTO productListDTO = CopyModuleClassUtils.bean2vo(goodsProduct, WXGoodsDetailVO.DataDTO.ProductListDTO.class);
            data.getProductList().add(productListDTO);
        }

        return wxGoodsDetailVO.success();
    }

    // 相似度匹配，自由发挥，这里先暂时返回给定的数据
    @Override
    public WXGoodsRelatedVO queryRelatedStuff(Integer id) {
        WXGoodsRelatedVO wxGoodsRelatedVO = new WXGoodsRelatedVO();
        wxGoodsRelatedVO.setData(new WXGoodsRelatedVO.DataDTO());
        wxGoodsRelatedVO.getData().setLimit(1);
        wxGoodsRelatedVO.getData().setPage(1);
        wxGoodsRelatedVO.getData().setTotal(1);
        wxGoodsRelatedVO.getData().setPages(1);
        wxGoodsRelatedVO.getData().setList(new LinkedList<>());
        Goods goods = goodsMapper.selectByPrimaryKey(id);
        WXGoodsRelatedVO.DataDTO.ListDTO listDTO = CopyModuleClassUtils.bean2vo(goods, WXGoodsRelatedVO.DataDTO.ListDTO.class);
        wxGoodsRelatedVO.getData().getList().add(listDTO);
        return wxGoodsRelatedVO.success();
    }

    private Integer deleteGoods(GoodsDeleteBo goodsDeleteBo) {
        Goods goods = new Goods();
        goods.setId(goodsDeleteBo.getId());
        goods.setUpdateTime(new Date());
        goods.setDeleted(true);
        goodsMapper.updateByPrimaryKeySelective(goods);
        goodsElasticsearchMapper.delete(goods);

        GoodsAttribute goodsAttribute = new GoodsAttribute();
        goodsAttribute.setGoodsId(goods.getId());
        goodsAttribute.setDeleted(true);
        goodsAttribute.setUpdateTime(goods.getUpdateTime());
        goodsAttributeMapper.updateByGoodsId(goodsAttribute);


        GoodsProduct goodsProduct = new GoodsProduct();
        goodsProduct.setGoodsId(goods.getId());
        goodsProduct.setDeleted(true);
        goodsProduct.setUpdateTime(goods.getUpdateTime());
        goodsProductMapper.updateByGoodsId(goodsProduct);


        GoodsSpecification goodsSpecification = new GoodsSpecification();
        goodsSpecification.setGoodsId(goods.getId());
        goodsSpecification.setDeleted(true);
        goodsSpecification.setUpdateTime(goods.getUpdateTime());
        goodsSpecificationMapper.updateByGoodsId(goodsSpecification);

        return 1;
    }

    @Override
    public Set<String> helpSearch(String keyword) throws IOException {
//        SearchRequest searchRequest = new SearchRequest(Constant.ES_GOODS);
//        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//        //MultiMatchQueryBuilder field = new MultiMatchQueryBuilder(keyword).field("name").field("keywords").field("brief");
//        MatchQueryBuilder name = new MatchQueryBuilder("name", keyword);
//        //sourceBuilder.query(field);
//        sourceBuilder.query(name);
//        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
//
//        searchRequest.source(sourceBuilder);
//        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//        ArrayList<String> helpList = new ArrayList<>();
//        for (SearchHit documentFields : searchResponse.getHits().getHits()) {
//            String sourceAsString = documentFields.getSourceAsString();
//            helpList.add(sourceAsString);
//            if(helpList.size() > 9){
//                break;
//            }
//        }
//
//        return helpList;

//        TermSuggestionBuilder termSuggestionBuilder = SuggestBuilders.termSuggestion("name").text(keyword).size(6);
//        SuggestBuilder suggestBuilder = new SuggestBuilder();
//        suggestBuilder.addSuggestion("name",termSuggestionBuilder);
//
//        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//        searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
//        searchSourceBuilder.suggest(suggestBuilder);
//
//        SearchRequest searchRequest = new SearchRequest(Constant.ES_GOODS);
//        searchRequest.source(searchSourceBuilder);
//
//        Set<String> data = new HashSet<>();
//        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//        Suggest suggest = searchResponse.getSuggest();
//        if(suggest != null) {
//            TermSuggestion result = suggest.getSuggestion("name");
//            for (TermSuggestion.Entry entry : result.getEntries()) {
//                for (TermSuggestion.Entry.Option option : entry.getOptions()) {
//                    if(option != null) {
//                        data.add(option.getText().toString());
//                    }
//                }
//            }
//        }
//        return data;

        /**
         * GET /goods_bak/_search
         * {
         *   "suggest":{
         *     "name":{
         *       "prefix":"羊",
         *       "completion":{
         *         "field":"name",
         *         "skip_duplicates":true,
         *         "size":10
         *       }
         *     }
         *   }
         * }
         */
        /*CompletionSuggestionBuilder completionSuggestionBuilder = new CompletionSuggestionBuilder("name")
                .prefix(keyword)
                .skipDuplicates(true)
                .size(5);
        SuggestBuilder suggestBuilder = new SuggestBuilder().addSuggestion("name_suggest", completionSuggestionBuilder);
        //构建request
        SearchRequest searchRequest = new SearchRequest(Constant.ES_GOODS);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
        searchSourceBuilder.suggest(suggestBuilder);
        searchSourceBuilder.fetchSource(false);
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        Suggest suggest = searchResponse.getSuggest();
        Suggest.Suggestion suggestion = suggest.getSuggestion("name_suggest");

        Set<String> data = new HashSet<>();
        List<CompletionSuggestion.Entry> entries = suggestion.getEntries();
        entries.forEach(entry -> {
            List<CompletionSuggestion.Entry.Option> options = entry.getOptions();
            options.forEach(op->{
                data.add(op.getText().toString());
            });
        });

        return data;*/

        SearchRequest searchRequest = new SearchRequest(Constant.ES_GOODS);
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        SuggestBuilder suggestBuilder = new SuggestBuilder();
        suggestBuilder.addSuggestion("normal", SuggestBuilders.completionSuggestion("name.normal")
                .prefix(keyword).skipDuplicates(true).size(5));
        suggestBuilder.addSuggestion("suggestText", SuggestBuilders.completionSuggestion("name.suggestText").prefix(keyword).skipDuplicates(true).size(5));
        suggestBuilder.addSuggestion("full_pinyin", SuggestBuilders.completionSuggestion("name.full_pinyin").prefix(keyword).skipDuplicates(true).size(5));
        suggestBuilder.addSuggestion("prefix_pinyin", SuggestBuilders.completionSuggestion("name.prefix_pinyin").prefix(keyword).skipDuplicates(true).size(5));
        suggestBuilder.addSuggestion("like_pinyin", SuggestBuilders.completionSuggestion("name.like_pinyin").prefix(keyword, Fuzziness.fromEdits(1)).skipDuplicates(true).size(5));
        sourceBuilder.suggest(suggestBuilder);
        sourceBuilder.timeout(new TimeValue(20, TimeUnit.SECONDS));
        searchRequest.source(sourceBuilder);
        HashSet<String> result = new HashSet<>();
        List<String> suggestList = Arrays.asList("normal", "suggestText", "full_pinyin", "prefix_pinyin", "like_pinyin");
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        Suggest suggestions = searchResponse.getSuggest();
        Integer index = 1;
        for (String suggestionType : suggestList) {
            CompletionSuggestion completionSuggestion = suggestions.getSuggestion(suggestionType);
            for (CompletionSuggestion.Entry entry : completionSuggestion.getEntries()) {
                for (CompletionSuggestion.Entry.Option option : entry) {
                    String suggestName = option.getHit().getSourceAsMap().get("name").toString();
                    result.add(suggestName);
                }
            }
            if (result.size() >= 5) break;
            if (index == 3 && result.size() > 0) break;
            if (keyword.length() > 3 && result.size() == 0) break;
        }
        return result;
    }

    private Integer getUserId() {
        Subject subject = SecurityUtils.getSubject();
        if (subject.getPrincipals() == null) {
            return null;
        }
        Object primaryPrincipal = subject.getPrincipals().getPrimaryPrincipal();
        return ((User) primaryPrincipal).getId();

    }

}